package com.hahaliu.hahaliu.common.utils;

import com.hahaliu.hahaliu.common.exception.BaseException;
import io.minio.*;
import io.minio.messages.Item;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.util.UUID;

@Data
@AllArgsConstructor
@Slf4j
public class MinioUtil {

	private String endpoint;
	private String accessKeyId;
	private String accessKeySecret;
	private String bucketName;

	/**
	 * 文件上传
	 *
	 * @param file
	 * @param folderName
	 * @param objectName
	 * @return
	 */
	public String upload(MultipartFile file, String folderName, String objectName) {

		MinioClient minioClient = MinioClient.builder()
				.endpoint(endpoint)
				.credentials(accessKeyId,accessKeySecret)
				.build();

		try {

			boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
			if (!bucketExists){
				// 如果不存在，就创建桶
				minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
			}

			// 上传文件到minio

			String fullObjectName = folderName + "/" + objectName;
			minioClient.putObject(PutObjectArgs.builder()
					.bucket(bucketName) // 存储桶
					.object(fullObjectName) // 文件名
					.stream(file.getInputStream(), file.getSize(), -1) // 文件内容
					.contentType(file.getContentType()) // 文件类型
					.build());
			
		} catch (Exception e) {
			log.error("上传文件失败:{}", e.getMessage());
		}

		// 创建文件返回地址
		StringBuilder stringBuilder = new StringBuilder(endpoint).append("/");
		stringBuilder.append(bucketName).append("/")
				.append(folderName).append("/")
				.append(objectName);

		log.info("文件上传到:{}", stringBuilder.toString());

		return stringBuilder.toString();

	}

	/**
	 * 文件删除
	 * @param fullObjectName
	 * @param folderName
	 */
	public void delete(String fullObjectName, String folderName) {
		MinioClient minioClient = MinioClient.builder()
				.endpoint(endpoint)
				.credentials(accessKeyId, accessKeySecret)
				.build();

		try {
			// 解析文件路径
			// 找到最后一个斜杠的位置
			int lastSlashIndex = fullObjectName.lastIndexOf("/");
			String objectName = fullObjectName.substring(lastSlashIndex + 1);

			// 删除对象
			minioClient.removeObject(RemoveObjectArgs.builder()
					.bucket(bucketName)
					.object(folderName + "/" + objectName)
					.build());
			log.info("文件删除成功: {}", fullObjectName);
		} catch (Exception e) {
			log.error("删除文件时出错: {}", e.getMessage());
		}
	}

	/**
	 * 查询指定前缀的文件数量
	 * @param folderName
	 * @param prefix
	 * @return
	 */
	public int countFiles(String folderName, String prefix) {

		MinioClient minioClient = MinioClient.builder()
				.endpoint(endpoint)
				.credentials(accessKeyId, accessKeySecret)
				.build();

		try {
			ListObjectsArgs args = ListObjectsArgs.builder()
					.bucket(bucketName)
					.prefix(folderName + "/" + prefix)
					.recursive(true)
					.build();

			Iterable<Result<Item>> results = minioClient.listObjects(args);
			int count = 0;
			for (Result<Item> result : results) {
				Item item = result.get();
				// 可以在这里处理每个对象（例如打印对象信息）
//				System.out.println("Object: " + item.objectName());
				count++;
			}
			return count;
		} catch (Exception e) {
			throw new BaseException("查询数量失败");
		}
	}

	/**
	 * 删除指定文件夹下指定前缀文件
	 * @param folderName
	 * @param prefix
	 */
	public void deleteFiles(String folderName, String prefix){

		MinioClient minioClient = MinioClient.builder()
				.endpoint(endpoint)
				.credentials(accessKeyId, accessKeySecret)
				.build();
		try {
			ListObjectsArgs args = ListObjectsArgs.builder()
					.bucket(bucketName)
					.prefix(folderName + "/" + prefix)
					.recursive(true)
					.build();

			Iterable<Result<Item>> results = minioClient.listObjects(args);

			for (Result<Item> result : results) {
				Item item = result.get();
				minioClient.removeObject(RemoveObjectArgs.builder()
						.bucket(bucketName)
						.object(item.objectName())
						.build());
//				System.out.println("删除文件" + item.objectName());
			}

		} catch (Exception e) {
			throw new BaseException("删除文件失败");
		}
	}

	/**
	 * 合并分片
	 * @param hash
	 * @return
	 */
	public String mergeChunks(String hash) {
		// 生成文件名
		String uuid = System.currentTimeMillis() + UUID.randomUUID().toString().replace("-", "");
		String fileName = uuid + ".mp4";

//		String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).replace("-", "");
		String filePathName = "video/" + fileName;

		MinioClient minioClient = MinioClient.builder()
				.endpoint(endpoint)
				.credentials(accessKeyId, accessKeySecret)
				.build();

		ListObjectsArgs args = ListObjectsArgs.builder()
				.bucket(bucketName)
				.prefix("chunk" + "/" + hash + "-")
				.recursive(true)
				.build();

		Iterable<Result<Item>> results = minioClient.listObjects(args);

		// 创建一个临时文件用来存储合并后的视频
		File mergedFile = new File("temp.mp4");

		try (FileOutputStream outputStream = new FileOutputStream(mergedFile)) {
			for (Result<Item> result : results) {
				byte[] data = IOUtils.toByteArray(minioClient.getObject(GetObjectArgs.builder()
						.bucket(bucketName)
						.object(result.get().objectName())
						.build()));
				// 写入当前分片的数据
				outputStream.write(data);
			}
		} catch (Exception e) {
			log.error("合并视频分片时出错: {}", e.getMessage());
		}

		// 上传合并后的视频文件到 Minio
		try {
			minioClient.uploadObject(UploadObjectArgs.builder()
					.bucket(bucketName)
					.object(filePathName)
					.filename(mergedFile.getAbsolutePath())
					.build());
		} catch (Exception e) {
			log.error("上传合并后的视频文件时出错: {}", e.getMessage());
		}

		// 删除临时文件
		if (mergedFile.exists()) {
			if (mergedFile.delete()) {
				log.info("删除临时文件成功");
			} else {
				log.info("删除临时文件失败");
			}
		}

		try {
			for (Result<Item> result : results) {
				Item item = result.get();
				minioClient.removeObject(RemoveObjectArgs.builder()
						.bucket(bucketName)
						.object(item.objectName())
						.build());
//				System.out.println("删除文件" + item.objectName());
			}
		} catch (Exception e) {
			log.error("删除所有分片失败: {}", e.getMessage());
		}

		// 创建文件返回地址
		StringBuilder stringBuilder = new StringBuilder(endpoint).append("/");
		stringBuilder.append(bucketName).append("/")
				.append(filePathName);

		log.info("文件上传到:{}", stringBuilder.toString());

		// 返回合并后的视频文件访问地址
		return stringBuilder.toString();
	}

}
